#ifndef TESTER_TEST_METHOD_H_
#define TESTER_TEST_METHOD_H_

#include <exception>

#include "exceptions.h"
#include "result.h"

namespace Tester {

   class TestMethod {
      public:
         virtual void run(Result *result, void *myself) = 0;
         virtual const char * name() const = 0;
         virtual ~TestMethod() {}
   };

   template<class T>
   class TestMethodMember : public TestMethod {
      private:
         const char * const _name;
         void (T:: *const testMethod)();

      public:

         TestMethodMember(const char * const name, 
               void (T:: *const testMethod)()) :
            _name(name), 
            testMethod(testMethod) {}

         virtual void run(Result *result, void *myself) {
            T* self = static_cast<T*>(myself);
            try {
               (self->*testMethod)();
               result->pass(_name);

            }catch(const AssertFail &fail) {
               result->fail(_name, self->checkpoint_count(), fail.type(), fail.line());

            }catch(const std::exception &e) {
               result->unexpected(_name, self->checkpoint_count(), e.what());
            
            }catch(...){
               result->unexpected(_name, self->checkpoint_count());
            }
         }

         inline const char * name() const { return _name; }
   };
}
#endif
